﻿using Basic.FormExtendService;
using Basic.FormRemoteModel;
using Basic.FormRemoteModel.UserForm.Model;
using Basic.HrRemoteModel.DicItem.Model;
using Basic.UserFormService.Calculate.Interface;
using Basic.UserFormService.Calculate.Model;
using Basic.UserFormService.Model;
using Flee.PublicTypes;
using WeDonekRpc.Helper;

namespace Basic.UserFormService.Calculate
{
    internal class FormDefStateCalculate : IFormDefStateCalculate
    {
        private readonly IDictService _Dict;
        public FormDefStateCalculate ( IDictService dict )
        {
            this._Dict = dict;
        }
        private FormGetArg _Arg;
        private UserFormBody _Form;
        private FormBodyDto _Body;
        private Dictionary<long, DicItem[]> _DicItem;
        private Dictionary<long, UserFormTable> _FormTable;
        public void InitColumnState ( FormBodyDto body, UserFormBody form, FormGetArg arg )
        {
            if ( body.StateFormula.IsNull() == false )
            {
                this._Arg = arg;
                this._Form = form;
                this._Body = body;
                this._DicItem = this._Dict.GetItemNames(body.StateDicId, body.TreeStateDicId);
                this._FormTable = form.Table.ToDictionary(a => a.Id, a => a);
                this._CalculateForm();
            }
        }
        private void _CalculateForm ()
        {
            this._Body.StateFormula.ForEach(a =>
            {
                UserFormTable table = this._FormTable[a.TableId];
                if ( table.TableType == FormTableType.单一表单 )
                {
                    bool res = this._Calculate(a);
                    if ( res )
                    {
                        this._Form.DefState.AddOrSet(a.ColId, this._Body.StateControl[a.ColId]);
                    }
                }
                else if ( !table.Rows.IsNull() )
                {
                    ExpressionContext exp = CalculateLinq.Clone();
                    if ( !a.VarCol.IsNull() )
                    {
                        if ( !this._InitVal(a.VarCol, exp) )
                        {
                            return;
                        }
                    }
                    table.Rows.ForEach(( row, index ) =>
                    {
                        bool res = this._Calculate(a, exp, index);
                        if ( res )
                        {
                            row.ColState ??= new Dictionary<long, FormStateControl>();
                            row.ColState.AddOrSet(a.ColId, this._Body.StateControl[a.ColId]);
                        }
                    });
                }
            });
        }
        private bool _Calculate ( ColFormula formula, ExpressionContext exp, int index )
        {
            using ( CurState state = CalculateLinq.SetCurrentState(index) )
            {
                IDynamicExpression expre = exp.CompileDynamic(formula.Formula);
                return (bool)expre.Evaluate();
            }
        }
        private bool _Calculate ( ColFormula formula )
        {
            ExpressionContext exp = CalculateLinq.Clone();
            if ( !formula.VarCol.IsNull() )
            {
                if ( !this._InitVal(formula.VarCol, exp) )
                {
                    return false;
                }
            }
            using ( CurState state = CalculateLinq.SetCurrentState(null) )
            {
                IDynamicExpression expre = exp.CompileDynamic(formula.Formula);
                return (bool)expre.Evaluate();
            }
        }
        private bool _InitVal ( ColFormulaVar[] vars, ExpressionContext exp )
        {
            return vars.TrueForAll(a =>
            {
                UserFormTable table = this._FormTable[a.TableId];
                if ( table.TableType == FormTableType.单一表单 )
                {
                    object val = null;
                    if ( table.Row != null )
                    {
                        val = table.Row.Values.GetValueOrDefault(a.Name);
                    }
                    else if ( !a.DefValue.IsNull() )
                    {
                        val = this._GetDefValue(a);
                    }
                    else
                    {
                        return false;
                    }
                    if ( val == null )
                    {
                        return false;
                    }
                    exp.Variables[a.Key] = this._FormatValue(val, a);
                    return true;
                }
                else if ( table.Rows.IsNull() )
                {
                    return false;
                }
                else
                {
                    object[] datas = table.Rows.ConvertAll(c => c.Values.GetValueOrDefault(a.Name));
                    if ( datas.IsNull() )
                    {
                        return false;
                    }
                    else
                    {
                        exp.Variables[a.Key] = this._FormatValue(datas, a);
                    }
                    return true;
                }
            });
        }
        private object _GetDefValue ( ColFormulaVar col )
        {
            if ( !col.DefValue.StartsWith("[") && !col.DefValue.EndsWith("]") )
            {
                if ( col.DataType == FormRecordDataType.Bool )
                {
                    return col.DefValue == "true";
                }
                else if ( col.DataType == FormRecordDataType.Number )
                {
                    return decimal.Parse(col.DefValue);
                }
                else if ( col.DataType == FormRecordDataType.Time || col.DataType == FormRecordDataType.Long )
                {
                    return long.Parse(col.DefValue);
                }
                else if ( col.DataType == FormRecordDataType.Date || col.DataType == FormRecordDataType.DateTime )
                {
                    return DateTime.Parse(col.DefValue);
                }
                return col.DefValue;
            }
            else if ( col.DefValue == "[curTime]" )
            {
                return DateTime.Now;
            }
            else if ( col.DefValue == "[comId]" )
            {
                return this._Arg.CompanyId;
            }
            else if ( col.DefValue == "[empId]" )
            {
                return this._Arg.EmpId;
            }
            return null;
        }
        private object[] _FormatValue ( object[] value, ColFormulaVar col )
        {
            if ( col.FuncType == DataFuncType.树形字典 || col.FuncType == DataFuncType.字典项 )
            {
                return value.ConvertAll<object, object>(a => new RecordVal
                {
                    value = a,
                    dataType = col.DataType,
                    funcType = col.FuncType,
                    dicItem = this._DicItem[col.DicId.Value]
                });
            }
            else if ( col.FuncType == DataFuncType.选项值 )
            {
                return value.ConvertAll<object, object>(a => new RecordVal
                {
                    value = a,
                    dataType = col.DataType,
                    funcType = col.FuncType,
                    items = this._Body.Items[col.ColId]
                });
            }
            return value;
        }
        private object _FormatValue ( object value, ColFormulaVar col )
        {
            if ( col.FuncType == DataFuncType.树形字典 || col.FuncType == DataFuncType.字典项 )
            {
                return new RecordVal
                {
                    value = value,
                    dataType = col.DataType,
                    funcType = col.FuncType,
                    dicItem = this._DicItem[col.DicId.Value]
                };
            }
            else if ( col.FuncType == DataFuncType.选项值 )
            {
                return new RecordVal
                {
                    value = value,
                    dataType = col.DataType,
                    funcType = col.FuncType,
                    items = this._Body.Items[col.ColId]
                };
            }
            return value;
        }
    }
}